package com.fresh.bus.chat.business;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.mail.internet.MimeMessage;

import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.collections.DefaultRedisZSet;
import org.springframework.data.redis.support.collections.RedisZSet;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

import com.fresh.bus.canoe.message.Response;
import com.fresh.bus.canoe.session.Session;
import com.fresh.bus.canoe.session.SessionRoleManager;
import com.fresh.bus.chat.ctrl.OpCodes;
import com.fresh.bus.chat.domain.AssoLog;
import com.fresh.bus.chat.domain.QingYiGuo;
import com.fresh.bus.chat.domain.TreeLog;
import com.fresh.bus.chat.domain.UserLog;
import com.fresh.bus.chat.domain.Water;
import com.fresh.bus.chat.persist.TreeDao;
import com.fresh.bus.chat.persist.UserDao;
import com.fresh.bus.chat.util.DateUtil;
import com.fresh.bus.chat.util.MessageUtils;

@Component
public class TreeService {

	private static final Logger log = LoggerFactory
			.getLogger(TreeService.class);

	@Resource
	private UserDao userDao;
	@Resource
	private TreeDao treeDao;
	@Resource
	private UserService userService;
	@Resource
	private MessageService msgService;
	@Resource
	private TreeLogService treeLogService;
	@Resource
	private ZhiFeiJiService feijiService;
	@Resource
	private UserLogService userLogService;
	@Resource
	private AssoValueService assoValueService;

	@Resource
	private EnergyService energyService;
	@Resource
	private WealthService wealthService;
	
	@Resource
	protected SessionRoleManager roleManager;
	@Resource
	private JavaMailSenderImpl javaMailSender;

	private StringRedisTemplate template;
	private ObjectMapper objectMapper = new ObjectMapper();

	public static final int UPGRADE_LEVEL_VALUE = 180;
	public static final int MAX_TREE_LEVEL = 5;

	public static final int ITASK_ACCEPT = 0;
	public static final int ITASK_CONFIRM = 1;

	public RedisZSet<String> trees;

	@Autowired
	public TreeService(StringRedisTemplate template) {
		this.template = template;
		trees = new DefaultRedisZSet(KeyUtils.trees(), template);
	}

	public void initTrees() {
		List<Map<String, Object>> posts = treeDao.getAllTrees();
		for (Map<String, Object> tree : posts) {
			try {
				createTreeInMem(tree);
			} catch (Exception ex) {
				log.error("Create tree failed for user:" + tree.get("owner"),
						ex);
				continue;
			}
		}
		log.info("Finish tree inital ...");
	}

	private void createTreeInMem(Map<String, Object> tree) {
		Map<String, String> map = treeDao.processData(tree);
		String id = map.get("owner");
		log.info("It is initlize tree:[" + id + "] in memory...");
		String tid = KeyUtils.tid(id);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(tid);
		ops.putAll(map);
		synTreesRank(map);
	}
	
	public void synTreesRank(Map<String,String> tree){
		String id = tree.get("owner");
		Date latestVisite = DateUtil.convertStringToDate(tree.get("updatedAt"));
		long loginTime = latestVisite.getTime();
		long score = loginTime / (1000 * 60);
		this.trees.add(id, score);
	}	

	// 取水
	public int gatherWater(String userId, int placeType) throws Exception {
		int period = MessageUtils.getPeriod();
		String uid = KeyUtils.uid(userId);
		BoundHashOperations<String, String, String> user = template
				.boundHashOps(uid);
		int weather = Integer.parseInt(user.get("weather"));
		int result = -2;
		int energy = Integer.parseInt(user.get("energy"));

		if (energy + EnergyService.GATHER_WATER_ENERGY < 0) {
			return result;
		}

		int v;
		switch (placeType) {
		case 1: // 普通居民区
			v = (int) (Math.random() * 99);
			if (v < 20) {
				result = Water.NOTHING;
				energyService.update(userId, EnergyService.GATHER_WATER_ENERGY);
			} else if (v >= 20 && v < 25) {
				result = Water.RESTORE;
				energyService.restore(userId);
			} else if (v >= 25 && v < 30) {
				result = Water.HURT;
				energyService.update(userId,
						EnergyService.GATHER_WATER_ENERGY * 2);
			} else {
				energyService.update(userId, EnergyService.GATHER_WATER_ENERGY);
				result = Water.getWater(period, weather);
			}
			break;
		case 2:// 大草原
			energyService.update(userId, EnergyService.GATHER_WATER_ENERGY);
			result = Water.getWater(period, weather);
			break;
		case 3:// 高山
			v = (int) (Math.random() * 99);
			if (v < 35) {
				result = Water.NOTHING;
				energyService.update(userId, EnergyService.GATHER_WATER_ENERGY);
			} else if (v >= 35 && v < 65) {
				result = Water.HURT;
				energyService.update(userId,
						EnergyService.GATHER_WATER_ENERGY * 2);
			} else if (v >= 65 && v < 90) {
				result = Water.RESTORE;
				energyService.restore(userId);
			} else {
				result = Water.SHANQUAN;
			}
			break;
		}

		if (result > 0) {
			addWater(userId, result);
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	private boolean addWater(String userId, int waterType) throws Exception {
		boolean isSucess = false;
		String uid = KeyUtils.uid(userId);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		String waterInfoStr = ops.get("waterInfo");
		List<Integer> waterInfo = this.objectMapper.readValue(waterInfoStr,
				List.class);

		int len = waterInfo.size();
		for (int i = len - 1; i >= 0; i--) {
			if (waterInfo.get(i) == 0) {
				waterInfo.set(i, waterType);
				isSucess = true;
				break;
			}
		}

		if (isSucess) {
			waterInfoStr = objectMapper.writeValueAsString(waterInfo);
			ops.put("waterInfo", waterInfoStr);
		}
		return isSucess;
	}

	@SuppressWarnings("unchecked")
	public String lostWater(String userId, int posIndex) throws Exception {
		String uid = KeyUtils.uid(userId);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		String waterInfoStr = ops.get("waterInfo");
		List<Integer> waterInfo = this.objectMapper.readValue(waterInfoStr,
				List.class);
		int waterType = waterInfo.get(posIndex);
		waterInfo.set(posIndex, 0);
		Collections.sort(waterInfo);// 重新排序
		waterInfoStr = objectMapper.writeValueAsString(waterInfo);
		ops.put("waterInfo", waterInfoStr);
		return String.valueOf(waterType);
	}

	// 送水
	public Map<String, Object> exchangeWater(String from, String to,
			int posIndex) throws Exception {
		String waterType;
		boolean isSuccess = false;
		String waterInfo = this.userService.findUser(to).get("waterInfo");
		if (waterInfo.indexOf("0") > -1) {
			waterType = this.lostWater(from, posIndex);
			this.addWater(to, Integer.valueOf(waterType));

			this.treeLogService
					.updateLog(to, from, TreeLog.SONGSHUI, waterType);
			this.assoValueService.update(from, to, AssoLog.PRESENT_WATER,
					waterType);
			this.wealthService.getFlower(from, Integer.valueOf(waterType));
			msgService.notifyTargetUser(to, from, UserLog.SONGSHUI, waterType);

			String tid = KeyUtils.tid(to);
			BoundHashOperations<String, String, String> ops = template
					.boundHashOps(tid);
			this.treeDao.updateTree(ops.entries());
			this.userService.saveUser(to);
			Map<String, String> u2 = this.userService.findUser(to);
			waterInfo = u2.get("waterInfo");
			// 邮件通知
			if (waterInfo.indexOf("0") <= -1) {
				sendMailForWaterEnough(u2.get("qqNo"));
			}
			isSuccess = true;
		}

		Map<String, Object> map = this.getTree(to);
		map.put("isSuccess", isSuccess);
		map.put("waterInfo", waterInfo);
		String myWaterInfo = this.userService.findUser(from).get("waterInfo");
		map.put("myWaterInfo", myWaterInfo);
		return map;
	}

	// 邮件通知水池已满
	private void sendMailForWaterEnough(String qqNo) {
		if (qqNo != null && qqNo.trim().length() > 4) {
			MimeMessage mimeMessage = javaMailSender.createMimeMessage();
			MimeMessageHelper helper = new MimeMessageHelper(mimeMessage);
			try {
				helper.setFrom("myfreshcity@163.com", "脱单名片");
				helper.setTo(qqNo + "@qq.com");
				helper.setSubject("【脱单名片】朋友们已将你的存水池装满，快来给梧桐树浇水啦！");
				helper.setText(
						"<p>有太多人在关心你呢！清水已装满了整个池子,再也盛不下更多的水了。<br/>赶快去给梧桐树浇水，顺便看看谁正在帮你？<a style=\"color:#0000FF;text-decoration: none;\" href=\"http://rc.qzone.qq.com/100711253\" target=\"_blank\">&nbsp;&nbsp;&gt;&gt;立刻去看看</a></p>",
						true);
				javaMailSender.send(mimeMessage);
			} catch (Exception e) {
				log.error("Send user[" + qqNo + "] mail failed...",e.getMessage());
			}
		}
	}

	// 浇水
	public String outWater(String userId, int posIndex) throws Exception {
		String waterType = this.lostWater(userId, posIndex);
		int plantValue = Water.findPlantValue(Integer.valueOf(waterType));

		if (!energyService.valid(userId, EnergyService.POURE_WATER_ENERGY)) {
			return "-2";
		}

		String tid = KeyUtils.tid(userId);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(tid);

		int treeValue = Integer.valueOf(ops.get("treeValue"));
		int newTreeValue = treeValue + plantValue;
		ops.put("treeValue", String.valueOf(newTreeValue));
		this.treeLogService.updateLog(userId, userId, TreeLog.JIAOSHUI,
				waterType);

		int treeLevel = (int) Math.ceil(newTreeValue
				/ TreeService.UPGRADE_LEVEL_VALUE);
		if (treeLevel >= TreeService.MAX_TREE_LEVEL) {
			this.treeLogService
					.updateLog(userId, userId, TreeLog.CHENGSHU, "0");
		}
		String now = DateUtil.convertDateToString(new Date());
		ops.put("updatedAt", now);
		Map<String,String> tree = ops.entries();
		synTreesRank(tree);
		this.treeDao.updateTree(tree);
		energyService.update(userId, EnergyService.POURE_WATER_ENERGY);
		// 同步树信息
		Response response = new Response(OpCodes.GET_MY_TREE);
		Session session = this.roleManager.getSession(userId);
		if (session != null) {
			Map<String, Object> map = getTree(userId);
			response.setData(map);
			session.send(response);
		}
		return waterType;
	}

	public Map<String, Object> initNewTree(String userId) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("user", userId);
		this.treeDao.addTree(map);
		map = treeDao.getTreeByUserId(userId);
		this.createTreeInMem(map);
		this.treeLogService.updateLog(userId, userId, TreeLog.ZAISHU, "0");
		String tid = KeyUtils.tid(userId);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(tid);
		this.treeDao.updateTree(ops.entries());

		// 自动广播开树飞机
		/*
		 * Map<String,Object> data = new HashMap<String, Object>(); String
		 * content = "我刚刚栽下梧桐树，欢迎大家参观访问。期待您的爱心馈赠哦。"; data.put("content",
		 * content); feijiService.createPost(data, userId,true);
		 */
		return getTree(userId);
	}

	public String findTree(long start) {
		String result = null;
		long end = Math.min(start + 1, this.trees.size());
		Set<String> set = this.trees.reverseRange(start, end);
		Iterator<String> it = set.iterator();
		if (it.hasNext()) {
			result = it.next();
		}
		return result;
	}

	public Map<String, Object> getTree(String userId) {
		Map<String, Object> map = new HashMap<String, Object>();
		String tid = KeyUtils.tid(userId);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(tid);

		int treeLevel = 0;
		int growDay = 0;
		int treeValue = 0;
		String treeLog = "[]";

		if (ops.size() > 0) {
			treeValue = Integer.valueOf(ops.get("treeValue"));
			treeLevel = (int) Math.floor(treeValue
					/ TreeService.UPGRADE_LEVEL_VALUE);
			treeLevel += 1;

			treeLog = ops.get("treeLog");
			String startTimeStr = ops.get("createdAt");
			Date startDate = DateUtil.convertStringToDate(startTimeStr);
			Date now = new Date();
			growDay = DateUtil.getDaysBetween(startDate, now);
			
			map.put("owner", userId);
			String waterInfo = this.userService.findUser(userId).get("waterInfo");
			map.put("waterInfo", waterInfo);
			map.put("growLevel", treeLevel);
			map.put("growValue", treeValue);
			map.put("growDay", growDay);
			map.put("treeLog", treeLog);// 打理日志
			List<String> donors = this.treeLogService.getDonors(treeLog);
			map.put("friendRank", donors.toArray());// 情意排名
		}

		return map;
	}

	// 写下心愿
	public Map<String, Object> writeXinYuan(String user, String content) {
		String tid = KeyUtils.tid(user);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(tid);
		treeDao.writeWish(user, content);

		// 计算情意果
		/*
		 * Date treeStartDate =
		 * DateUtil.convertStringToDate(ops.get("createdAt")); Date now = new
		 * Date(); int diffDay = DateUtil.getDaysBetween(treeStartDate, now); if
		 * (diffDay < 5) { Session session = this.roleManager.getSession(user);
		 * Response response = new Response(OpCodes.INIT_QINGYI); String treeLog
		 * = ops.get("treeLog"); List<String> donors =
		 * this.treeLogService.getDonors(treeLog);// 计算贡献值 if
		 * (!donors.isEmpty()) { response.setData(donors.toArray());
		 * session.send(response); } }
		 */

		// 清除果树状态
		ops.put("status", "1");
		this.treeLogService.updateLog(user, user, TreeLog.SHOUHUO, "0");
		this.treeDao.updateTree(ops.entries());
		this.trees.remove(user);
		this.template.delete(tid);

		return this.getTree(user);
	}

	// 选择情意果
	public void openQingYi(String from, String to) {
		int taskType = QingYiGuo.getFruit();
		// 交换任务交互方式
		if (taskType > 100) {
			String temp = from;
			from = to;
			to = temp;
		}
		String id = DateUtil.getDateTime("MMddHHmmss", new Date());
		// 存储并通知
		addInteractTask(from, id, taskType, to, TreeService.ITASK_CONFIRM);
		addInteractTask(to, id, taskType, from, TreeService.ITASK_ACCEPT);
		// 记录用户日志
		String taskTypeStr = String.valueOf(taskType);
		this.userLogService.updateLog(from, to, UserLog.CONFIRM_ITASK,
				taskTypeStr);
		this.userLogService.updateLog(to, from, UserLog.ACCEPT_ITASK,
				taskTypeStr);

		this.userService.saveUser(from);
		this.userService.saveUser(to);
	}

	private void addInteractTask(String owner, String taskId, int taskType,
			String target, int status) {
		String uid = KeyUtils.uid(owner);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		String taskStr = ops.get("iTasks");
		Map<String, Object> task = new HashMap<String, Object>();
		try {
			List<Object> taskList = objectMapper.readValue(taskStr, List.class);
			task.put("id", taskId);
			task.put("t", target); // 交互对象
			task.put("d", taskType); // 任务描述
			task.put("s", status); // 状态
			taskList.add(task);
			taskStr = objectMapper.writeValueAsString(taskList);
			ops.put("iTasks", taskStr);

			Session session = this.roleManager.getSession(owner);
			if (session != null) {
				Response response = new Response(OpCodes.SYN_ITASK);
				response.setData(taskList.toArray());
				session.send(response);
			}
		} catch (Exception e) {
			log.error("add interact task for user:" + owner, e);
		}
	}

	private void removeInteractTask(String id, String user) {
		String uid = KeyUtils.uid(user);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		String taskStr = ops.get("iTasks");
		try {
			Map<String, Object> task;
			String tid;
			List<Object> taskList = objectMapper.readValue(taskStr, List.class);
			for (Object t : taskList) {
				task = (Map<String, Object>) t;
				tid = (String) task.get("id");
				if (tid.equals(id)) {
					taskList.remove(t);
					break;
				}
			}
			taskStr = objectMapper.writeValueAsString(taskList);
			ops.put("iTasks", taskStr);

			Session session = this.roleManager.getSession(user);
			if (session != null) {
				Response response = new Response(OpCodes.SYN_ITASK);
				response.setData(taskList.toArray());
				session.send(response);
			}
		} catch (Exception e) {
			log.error("add interact task for user:" + user, e);
		}
	}

	public List<Object> getITasks(String user) {
		List<Object> taskList = new ArrayList<Object>();
		String uid = KeyUtils.uid(user);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		String taskStr = ops.get("iTasks");
		try {
			taskList = objectMapper.readValue(taskStr, List.class);
		} catch (Exception e) {
			log.error("get interact task for user:" + user, e);
		}
		return taskList;
	}

	// 显示心愿
	public List<Map<String, Object>> getWishs(String user) {
		return this.treeDao.getUserWish(user);
	}

	// 确认完成互动任务
	public void confirmTask(String from, String to, String taskId) {
		this.removeInteractTask(taskId, from);
		this.removeInteractTask(taskId, to);

		this.userService.saveUser(from);
		this.userService.saveUser(to);
	}
}
